<?php
/**
 * Description:
 * Author: hezhizheng
 * Date: 2018/11/19
 * Time: 13:54
 * Created by Created by Panxsoft.
 */

namespace App\Http\Controllers\Api\V1\App\Customers;

use App\Http\Controllers\ApiController;
use App\Http\Requests\Customers\Address\AddressCreateRequest;
use App\Http\Requests\Customers\Address\AddressStoreRequest;
use App\Http\Requests\Customers\Address\AddressUpdateRequest;
use App\Http\Services\Api\V1\App\Product\OrderService;
use App\Models\Order\Address;
use App\Models\Customers\Customer;
use App\Models\Location\City;
use App\Models\Location\Country;
use App\Models\Location\Zone;
use App\Services\Locale\Language;
use App\Services\Utils\Guard;
use App\Services\Utils\Transaction;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Http\Request;

class AddressController extends ApiController
{

    /**
     * @var Customer
     */
    protected $customer;
    protected $order_service;

    public function __construct()
    {
        $this->customer = Guard::customer();
        $this->order_service = new OrderService;
    }

    /**
     *  app端个人中心，客户地址列表
     *
     * @return array|\Illuminate\Http\Response
     */
    public function index()
    {
        $addresses = $this->order_service->getCustomerAddress($this->customer);

        return $this->response(compact('addresses'));
    }

    /**
     * app端个人中心，返回区域地址选项
     *
     * @param AddressCreateRequest $request
     *
     * @return array|\Illuminate\Http\Response
     * @throws \Exception
     */
    public function create(AddressCreateRequest $request)
    {
        $address_data = $this->createAddressByType($request);

        return $this->response(compact('address_data'));
    }

    /**
     * 返回全部区域选项
     * @return array|\Illuminate\Http\Response
     */
    public function createAll()
    {
        $countries = (new Country)->get();
        $zones = (new Zone)
            ->get();
        $cities = (new City)
            ->where('up_id', City::UP_ID_TOP)
            ->oldest('sort_order')
            ->get();
        $counties = (new City)
            ->where('up_id', '<>', City::UP_ID_TOP)
            ->oldest('sort_order')
            ->get();

        return $this->response(compact('countries', 'cities', 'counties', 'zones'));
    }

    /**
     * app端个人中心，客户更新地址信息。
     *
     * @param AddressUpdateRequest $request
     * @param int $address_id
     *
     * @return array|\Illuminate\Http\Response
     * @throws \App\Exceptions\ApiAbstractException
     */
    public function update(AddressUpdateRequest $request, int $address_id)
    {
        $address = $this->checkFindAddress($address_id);

        $address_id = $this->customer->address_id;

        $req_data = $request->extractByRules(['is_default']);
        $save_data = $req_data + Address::defaultFields();


        $updated = $address->update($save_data);
        if ($request->is_default || !$address_id) {
            $this->customer->update(['address_id' => $address->getKey()]);
        }

        return $this->responseAccepted(compact('address', 'updated'));
    }

    /**
     * app端个人中心，客户新增地址信息。
     *
     * @param AddressStoreRequest $request
     *
     * @return array|\Illuminate\Http\Response
     * @throws \Exception
     */
    public function store(AddressStoreRequest $request)
    {
        $address_id = $this->customer->address_id;

        $is_default = $request->is_default;
        $req_data = $request->extractByRules(['is_default']);
        $save_data = ['customer_id' => $this->customer->getKey()] + $req_data + Address::defaultFields();

        $address = Transaction::handle(function() use($save_data, $is_default, $address_id){
            $address = (new Address)->create($save_data);
            if ($is_default || !$address_id) {
                $this->customer->update(['address_id' => $address->getKey()]);
            }

            return $address;
        });


        return $this->responseCreated(compact('address'));
    }

    /**
     * app端个人中心，客户删除地址信息。
     *
     * @param int $address_id
     *
     * @return array|\Illuminate\Http\Response
     * @throws \App\Exceptions\ApiAbstractException
     * @throws \Exception
     */
    public function destroy(int $address_id)
    {
        $address = $this->checkFindAddress($address_id);
        $this->checkUnless($this->customer->address_id === $address_id, trans('address.can_not_delete_default'));

        $deleted = $address->delete();
//        if ($this->customer->address_id === $address_id) { // clear Default
//            $this->customer->update(['address_id' => Customer::ADDRESS_ID_EMPTY]);
//        }

        return $this->responseAccepted(compact('address', 'deleted'));
    }

    /**
     * @param int $address_id
     *
     * @return Address
     * @throws \App\Exceptions\ApiAbstractException
     */
    private function checkFindAddress(int $address_id): Address
    {
        $address = (new Address)->find($address_id);
            $this->checkItemExist($address, 'address');
            $this->checkCanOperate($address->customer_id === $this->customer->getKey(),
                trans('address.customer_not_match'));

        return $address;
    }

    /**
     * @return Country[]|\Illuminate\Database\Eloquent\Collection
     */
    private function getCountry(): Collection
    {
        $country_data = (new Country)
            ->where('status', Country::COUNTRY_STATUS_ON)
            ->get();

        return $country_data;
    }

    /**
     * @param $country_id
     * @return Zone[]|\Illuminate\Database\Eloquent\Collection
     */
    private function getZone(int $country_id): Collection
    {
        $province_data = (new Zone)
            ->where('country_id', $country_id)
            ->where('status', Zone::ZONE_STATUS_ON)
            ->get();

        return $province_data;
    }

    /**
     * @param $zone_id
     *
     * @return City[]|\Illuminate\Database\Eloquent\Collection
     */
    private function getCity(int $zone_id): Collection
    {
        $city_data = (new City)
            ->where('up_id', City::CITY_UP_ID_ZERO)
            ->where('zone_id', $zone_id)
            ->where('status', City::CITY_STATUS_ON)
            ->get();

        return $city_data;
    }

    /**
     * @param $up_id
     *
     * @return City[]|\Illuminate\Database\Eloquent\Collection
     */
    private function getCounty(int $up_id): Collection
    {
        $town_data = (new City)
            ->where('up_id', $up_id)
            ->where('status', City::CITY_STATUS_ON)
            ->get();

        return $town_data;
    }

    /**
     * @param AddressCreateRequest $request
     *
     * @return City[]|Country[]|Zone[]|Collection
     *
     * @throws \Exception
     */
    private function createAddressByType(AddressCreateRequest $request): Collection
    {
        switch ($request->type) {
            case AddressCreateRequest::TYPE_COUNTRY :
                return $this->getCountry();

            case AddressCreateRequest::TYPE_CITY :
                return $this->getCity($request->up_id);

            case AddressCreateRequest::TYPE_COUNTY :
                return $this->getCounty($request->up_id);

            case AddressCreateRequest::TYPE_ZONE :
                return $this->getZone($request->up_id);

            default:
                $this->checkFailed('invalidate request type');
        }
    }
}